Skip to content

3/3 Add harness-engineering-bench (GAIA + benchmarks) - #46

Merged
varunursekar merged 186 commits into
mainfrom
pr3-harness-bench
Jul 28, 2026
Merged

3/3 Add harness-engineering-bench (GAIA + benchmarks)#46
varunursekar merged 186 commits into
mainfrom
pr3-harness-bench

Conversation

@varunursekar

@varunursekar varunursekar commented Jul 23, 2026

Copy link
Copy Markdown
Collaborator

Third of three stacked PRs splitting #41. Base: pr2-add-vero.

Adds harness-engineering-bench/ with each benchmark as a top-level sibling (gaia, ale-bench, officeqa, swe-atlas-qna, tau3) + scripts. Pure adds (71 files).

Union of 1/3 + 2/3 + 3/3 == v0.5 plus a legacy/ archive (verified).

🤖 Generated with Claude Code

Greptile Summary

This is the third of three stacked PRs that together compose v0.5, adding harness-engineering-bench/ with six benchmark integrations (GAIA, BrowseComp-Plus, OfficeQA, SWE-Atlas-QnA, tau3, SWE-bench-Pro), shared utility scripts, and a legacy/ archive. All 358 files are pure additions.

  • Each benchmark ships a baseline agent (OpenAI Responses or Chat Completions API), a build.yaml task configuration, deterministic partition files, and a task-building or partition script — the overall structure is consistent and well-documented.
  • The SWE-bench-Pro agent is the most complete: it includes retry-with-backoff, a path-traversal guard in _repo_relative, a UnicodeDecodeError trap for binary shell output, and correct turn-budget handling that grades repo state rather than raising. However, it shares with the other non-GAIA agents a missing guard for the empty-reasoning-output path (no tool calls, no visible text), which prematurely terminates the loop for o-series models that exhaust max_output_tokens on internal thinking.
  • Utility scripts (rescore_candidate.py, recover_producer_tokens.py, partition_dataset.py) are well-structured and safe; several issues across tau3, OfficeQA, BrowseComp-Plus, ALE-bench, and per_trial_tokens.py were identified in the earlier PRs of this stack.

Confidence Score: 4/5

Safe to merge for the infrastructure additions; the SWE-bench-Pro agent contains one reasoning-budget edge case that causes silent early termination rather than a crash, which will cost trial quality on hard tasks but does not block other benchmarks.

The SWE-bench-Pro agent breaks the turn loop whenever calls is empty, without checking whether output_text is also empty. An o-series model at reasoning_effort high with max_output_tokens 12000 can legitimately exhaust its output budget on internal reasoning and return neither tool calls nor visible text — the agent then exits and submits whatever partial edits exist in the repository, silently losing the rest of the turn budget. The correct behavior (as implemented in the GAIA agent) is to nudge the model and continue the loop. This is a real defect on the changed path, not a theoretical future risk.

Files Needing Attention: harness-engineering-bench/swe-bench-pro/baseline/target/src/swebench_pro_agent/agent.py — the empty-output early-exit path at line 491

Important Files Changed

Filename Overview
harness-engineering-bench/swe-bench-pro/baseline/target/src/swebench_pro_agent/agent.py Code-editing baseline using the Responses API with retry logic and path-traversal guards; correctly handles turn-budget exhaustion but silently exits when the model uses all reasoning tokens on an internal thinking step without producing output or a tool call.
harness-engineering-bench/gaia/baseline/target/src/gaia_agent/agent.py GAIA research baseline using the Responses API; nudges the model on empty turns and has a best-effort forced-final answer on budget exhaustion — the most robust error handling of all agents in this PR.
harness-engineering-bench/scripts/rescore_candidate.py Utility script to re-score a candidate from a salvaged session; mirrors the baseline's harbor invocation exactly, with safe tarfile extraction and deterministic version resolution.
harness-engineering-bench/scripts/partition_dataset.py Deterministic stratified partition generator for Harbor-native benchmarks (swe-atlas-qna, tau3); handles stratum allocation with exact-count enforcement and SHA-256 keyed stable sort.
harness-engineering-bench/browsecomp-plus/task-template/tests/evaluate.py LLM-based semantic verifier using the Responses API; exception handling is broad but str.format() with user-controlled substitution values is a latent crash risk previously flagged.
harness-engineering-bench/swe-bench-pro/baseline/build.yaml Build configuration for SWE-bench-Pro; correctly uses a single extra_harbor_args key (no duplication), proper timeouts, and well-scoped agent access controls.

Sequence Diagram

sequenceDiagram
    participant H as Harbor Harness
    participant A as Agent (run())
    participant API as OpenAI / Responses API
    participant E as Task Environment

    H->>A: run(instruction, environment, context)
    loop "turn = 1..MAX_TURNS"
        A->>API: responses.create(model, input, tools, ...)
        API-->>A: response (output_text, function_calls)
        alt function_calls empty AND output_text has content
            A->>E: _submit / verifier grades repo
            A-->>H: context.metadata set, break
        else function_calls empty AND output_text empty
            note over A: GAIA: nudge and continue<br/>SWE-bench-Pro: break (silent early exit)<br/>Others: RuntimeError
        else function_calls present
            loop each tool call
                A->>E: exec / upload / download
                E-->>A: result
            end
            A->>API: next_input (tool outputs)
        end
    end
    note over A: turn budget exhausted
    A-->>H: context.n_input_tokens, context.n_output_tokens
Loading

Reviews (70): Last reviewed commit: "Gate reasoning.effort on the forced-fina..." | Re-trigger Greptile

Introduce the v0.5 codebase: vero/ (core + harbor eval sidecar, build
compiler, runtime/observability), vero-tasks/, and runs/. Root README points
to legacy/ for the original-paper code.
@socket-security

socket-security Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedpypi/​tqdm@​4.68.49810010010070
Addedpypi/​tqdm@​4.69.09810010010070
Addedpypi/​tqdm@​4.69.19810010010070
Addedpypi/​click@​8.4.296100100100100
Addedpypi/​uvicorn@​0.51.098100100100100
Addedpypi/​tiktoken@​0.13.099100100100100
Addedpypi/​requests@​2.34.299100100100100
Addedpypi/​fastapi@​0.139.2100100100100100
Addedpypi/​fastapi@​0.140.0100100100100100

View full report

Comment thread harness-engineering-bench/ale-bench/environment/sidecar/dind-entrypoint.sh Outdated
varunursekar and others added 3 commits July 23, 2026 11:51
…back #1)

Addresses the 'baseline floor fails open' regression:
- baseline_floor now defaults to false. The floor gates a ship on a
  validation comparison while the reward is on the (possibly
  differently-distributed) target, so it is opt-in.
- Pin the fixed seed's score to avoid re-scoring it every run
  (reproducibility + one fewer eval): VerificationTarget.baseline_reward
  (per-target, post scale/offset) and VerificationSelection
  .baseline_selection_score (for the floor). Plumbed through the build
  config + compiler.
- Fail safe when the floor is on, unpinned, and the seed re-score can't be
  measured: ship nothing (NoCandidateError -> shipped=false + infra error)
  instead of shipping the best candidate unverified (the fail-open bug).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#1)

Add an admin-only way to generate the number to pin: CanonicalVerifier
.measure_baseline(replicates) admin-scores the fixed seed N times on the
selection partition and each target and returns per-key mean/stddev. Exposed
as POST /score/baseline and 'vero harbor score-baseline --replicates N'.
Reuses the existing admin scoring machinery.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…atten

The benchmark-config tests read harness-engineering-bench/ (a separate branch
in the stacked split), so skip them when it isn't checked out. Update the
paths for the candidates/ -> top-level flatten (all benchmarks are now
top-level siblings of gaia/).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
min_aggregate_cases defaulted to 1 — a vacuous floor that let an agent read
held-out validation labels one case at a time via single-case aggregate
evals. Default to 5 in both the sidecar policy and the build AgentAccessSpec
so a build that omits it is safe rather than unfloored (shipped builds
already set 5 explicitly).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Re-enabling harness isolation broke the eval: 'uv run' as the unprivileged
harness got a fresh empty uv cache and couldn't resolve the candidate package
from it (No module named 'gaia_agent'), with no network to download at eval
time. Pre-warm /home/harness/.cache/uv from the build (root) cache in the
sidecar image, matching the UV_CACHE_DIR the backend sets for the harness user.

Also fixes a test regression from feedback #2: with the k-anonymity floor
defaulting to 5, the instruction now reads 'must include at least 5 cases'
rather than 'arbitrary subsets'.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
varunursekar and others added 2 commits July 23, 2026 13:06
…ack #8)

The mean-of-k recorded only score/n_attempts/n_scored, so an outage-diluted
cell (dead attempts zero-filled) was indistinguishable from a genuinely clean
low cell. Add n_dead_infra (dead-to-infrastructure attempts, classified via
the existing error taxonomy) and n_clean (the rest), so the split is visible
in the live metrics rather than only reconstructable from raw trial records.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- optimizer.run: validate self.max_proposals >= 0 before the proposal_limit
  guard, so the specific 'must be non-negative' error is reachable (was a
  dead branch that always tripped the generic message first).
- compiler._safe_extract_tar: extractall(filter='data') to strip device
  files / setuid bits and neutralize unsafe links, matching
  extract_harbor_session_archive (also silences the py3.14 deprecation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
varunursekar and others added 5 commits July 23, 2026 13:27
A cold-start walkthrough of the harbor path: the three-container trust
boundary, a run end-to-end, the evaluation core, disclosure/selection, the
five security mechanisms, and a suggested outside-in review order keyed to
the source files.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update harbor_requirement pin from harbor[modal]==0.18.0 to ==0.20.0
across the README and harbor tests. Remove the PYTHONPATH injection in
the harness eval launch: it was a no-op (uv strips PYTHONPATH from the
child env) and did not fix the "No module named <agent>" failure under
the dropped uid, so it and its test assertion are gone.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The candidate is checked out at <mktemp>/repository; `mktemp -d` makes
that parent 0700 root. The eval launch chowned the repository (and the
staging tree) to the harness user but not the mktemp parent, so once the
process dropped to harness it could not traverse into its own workspace
to resolve the editable candidate package's absolute path — every eval
(baseline included) failed with "No module named <agent>" while harbor
itself still loaded from the harness-owned cache.

Grant the harness user traversal on that parent (chmod o+x) alongside the
existing chowns. o+x suffices because run_as drops to the user's own
uid+gid, so it is "other" relative to the root-owned parent. The dir
holds only candidate code, so widening traversal leaks no trusted data.

Reproduced and fixed against the real compiled sidecar image with a
faithful user+group+extra_groups privilege drop: 0700 -> "No module
named gaia_agent"; 0701 -> import resolves.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a reachability probe: after chowning/granting traversal, run `test -r
<project_path>` as the dropped user before launching harbor. Readability
requires traversing every ancestor, so any provisioning gap (a missing
chown, a non-traversable parent) is caught here with a clear message
instead of resurfacing as a cryptic "No module named <agent>" several
retries downstream — which is exactly how the checkout-parent bug hid.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the harness provisioning commands and reachability probe into
vero.harbor.isolation as a single source of truth, and have the eval
launch use them, so the runtime and the test can't drift.

Add tests/test_v05_harbor_isolation_container.py: inside a throwaway
Linux container it loads the real sandbox.py + isolation.py standalone
(stdlib-only, no install) and asserts, against the real uid/gid drop and
the real provisioning commands, that (1) a checkout under a 0700 mktemp
parent is unreachable to the dropped user when only the leaf is chowned
(the regression sentinel for the shipped bug), (2) it becomes reachable
after harness_grant_commands and the probe agrees, and (3) trusted
root-only state stays unreadable to the dropped user. Skips when no
docker daemon is available.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread harness-engineering-bench/ale-bench/environment/sidecar/harness/score.py Outdated
varunursekar and others added 2 commits July 23, 2026 17:08
Agents don't know what "vero" is; every name they meet should say what it
holds. The workspace context directory is now .evals/ with results/ (was
evaluations/), tasks/ (was cases/), and plan.json (was evaluations.json).
Host-side paths (~/.vero, ./.vero/session) are operator-facing and unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
One well-named entry point over the .evals/ context — the new avatar of the
legacy VeroAgent's three structured tools. Runner subcommands (run/status/
result/submit) delegate to the sidecar client lazily; the viewers (list/show/
cases/trace/diff/plan/tasks) are unprivileged stdlib readers of the disclosure-
projected tree, with bounded, paginated, metadata-first output. The compiler
bakes skills/evals/SKILL.md into the optimizer workspace by default
(include_evals_skill), and the instruction template now teaches `evals`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
varunursekar and others added 2 commits July 23, 2026 17:35
min_aggregate_cases moves onto the core EvaluationAccessPolicy (omitted
resolves to 5 under aggregate disclosure, 1 otherwise) and the engine refuses
agent-chosen aggregate subsets below the floor after cost resolution, so the
protection holds on every path — programmatic API and local runs included —
not just compiled harbor deployments. The sidecar keeps its earlier check as
defense-in-depth and now passes the floor through its explicit authorization.

AgentAccessSpec.to_access_policy() is the single typed translation from build
spec to runtime policy; the compiler emits it nested in serve.json and
SidecarEvaluationPolicy holds it as `access`, replacing the hand-rolled flat
keys (disclosure/agent_evaluable/min_aggregate_cases/expose_case_resources)
that had to be kept in sync across three representations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sidecar's context writer predates the .evals rename and had its own
literals: exposed task resources landed in .evals/cases/ (README, skill,
and instruction docs all say tasks/) and plan.json was never written in
the harbor topology, breaking the documented 'evals plan' first step.
Caught live in the first gaia run of the new stack.
varunursekar and others added 9 commits July 28, 2026 11:15
Greptile's summary review (confidence 4/5) flagged the real gap:
validate_optimizer_harbor_args guarded `-a`, `-e`, `-m`, `-p` but none of
their long forms. Build-declared args are appended after vero's own and harbor
takes the last value for a key, so a build carrying `--agent other` silently
replaced the agent the caller asked for -- a substitution that invalidates a
result without failing anything, which matters when the whole point of a grid
cell is which harness ran.

The review named `--environment`; harbor has no such option and spells the long
form of `-e` as `--env`, so that is what is reserved. Probed each flag against
`harbor run` rather than trusting the help table, which truncates.

`extra_harbor_args` had the same gap plus the inverse one: it reserved
`--jobs-dir` while leaving `-o`, the short form of the same flag, open. Both
validators now derive from one shared set so the two cannot drift again --
drift being the actual defect here, not any single missing string.

Matching stays exact rather than by prefix, because
`--agent-timeout-multiplier`, `--agent-kwarg` and
`--environment-build-timeout-multiplier` are all legitimate and all begin with
a reserved name; there are now tests pinning that they still pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Its evaluations were running entirely off-gateway. The live run shows 8
completed evaluation jobs, 0 requests in the gateway's evaluation scope, and
case metrics carrying only `agent_reported_*` tokens -- 41.3M input against an
allow-list that was never consulted.

Cause is one missing lookup. browsecomp-plus sets
`task_services_use_upstream`, which exists so an in-container grader can reach
the provider and does that by pointing OPENAI_* at the real upstream; the
candidate agent's metered credential then arrives only on
VERO_AGENT_INFERENCE_*. tau3 and swe-atlas-qna read those. browsecomp-plus
did not, so it fell through to OPENAI_* and ran on the raw upstream
credential: unmetered, unbudgeted, and with the pinned target model
unenforced.

Checked the consequence rather than assuming it: the shipped candidate from
the +0.169 run touches only search strategy -- turn cap, snippet size, dedup
-- and never the model or credentials, so that result stands as a harness
improvement. The capability to change the model was simply unguarded, which is
luck rather than a property, and 10 contestants x 3 repeats is a lot more
chances to stumble into it.

The existing config-level test could not catch this: the build does declare a
gateway and vero injects the upstream on purpose, so it passed throughout. The
new test asserts against the agent source instead, skips benchmarks that do not
reroute, and imports the env var names from vero.harbor.backend so it cannot
drift from the contract. Verified it fails with the agent fix reverted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A five-agent review of the suite turned up two documented safety guarantees
that the enforcing code contradicts. Both are in the files a colleague reads
first, and a false assurance is worse than no assurance.

CONFIGURATION.md said the evaluation allow-list fixes the target model "so a
candidate cannot swap it". gateway/inference.py carries a note, at the exact
line that enforces it, saying this is explicitly not a hard guarantee: both
scopes share one gateway host split only by URL path, and the optimizer holds
the producer token and authors the candidate. The doc now states the real
property and points at that note.

SKILL.md said "The optimizer never sees the real upstream key. Keep it that
way." Three of the five promoted benchmarks set task_services_use_upstream,
which puts the raw upstream credential into the evaluation sub-run, and those
three also run the candidate harness without a separate user -- an exposure
swe-atlas-qna's own build.yaml labels "ACCEPTED EXPOSURE". The skill now names
both caveats up front rather than hedging one of them 200 lines later.

Three factual corrections a reader would otherwise act on: the pinned
baseline_reward is inert at runtime (verified against a live run's
finalize.json, which carries an empty baseline_rewards, because the verifier
reads the pin only inside its score_baseline branch); max_concurrency is
concurrent trials, not cases, so 24 is 8 cases in flight once the test target
runs 3 attempts; and the token caps are 4.4-6.8M per case-run, 3.3-5.1x the
worst measured cost, not the stated ~3M and 2.3x.

Also corrected a claim I introduced earlier today: an omitted finalization
scope does not let search starve held-out scoring. The compiler mints that
token unconditionally and the gateway keys each ledger by scope, so an unset
scope gets its own pool at evaluation's size. The starvation incident predates
the reserved scope.

Finally, swe-bench-pro sits at the top level, which this README defines as
meaning promoted, while being absent from the promoted table and from every
column of CONFIGURATION.md. It is now explicitly marked unpromoted, with the
specific conventions it misses, because launching it yields a number that is
not a measurement of the same quantity.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The library README now leads with a run that actually happened, through the
contained path rather than the local one: mini-swe-agent with sonnet-5 on
harbor-circle-packing, 0.9598 to 2.5766 on the held-out partition, shipped
true, from a 15 KB Lubachevsky-Stillinger growth algorithm with LP refinement.
The figure is generated from the run's own session by a stdlib-only script, so
it regenerates rather than being a drawing.

It also records what the same task did without a prohibition on hardcoding:
codex scored 2.6360 in eight minutes by copying the published Packomania table
into 26 coordinate literals. Higher than the honest run, and held-out scoring
cannot tell the difference, because every partition holds one deterministic
case so a memorized answer transfers perfectly. instruction.md now forbids it.
That contrast is the more useful thing to put in front of a reader than either
number alone.

One detail in the figure earns its place: an infeasible candidate, rejected on
the `valid == 1` constraint, immediately followed by the agent's own "Add
safety margin to guarantee strict feasibility" commit. The constraint did work.

The verifier now reports a pinned baseline_reward whether or not
`score_baseline` is set. That flag decides whether the seed is *scored*, which
is expensive; it should not decide whether the run states the number every
delta is measured against. Read only inside the score_baseline branch, the pin
left every `score_baseline: false` run -- which is all five promoted
benchmarks -- shipping an empty `baseline_rewards`, confirmed against a live
officeqa finalization. Test reverted to check it fails without the fix.

Also here: the native optimizer falls back to OPENAI_* when LITELLM_* is
unset, since only reading the latter meant a standard environment posted to a
route the proxy does not serve and returned a 403 that reads as an auth error;
the session mismatch error now names the differing field and the remedy,
because a changed optimizer.model is enough to trigger it; the root README
answers "where is the paper code" once instead of twice; both mermaid diagrams
are replaced with one ASCII figure of the actual pieces; and
harbor-circle-packing documents the two prerequisites that cost three failed
starts today -- the required -p, and vendoring vero into the build context.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The note added earlier today said the pin was inert at runtime, which was true
when written: the verifier read `target.baseline_reward` only inside its
`score_baseline` branch, so all five promoted benchmarks shipped an empty
`baseline_rewards`. pr2 fixed that, so the doc now says the pin is reported in
`finalize.json` and flags that runs before 2026-07-28 carry an empty field.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Greptile (5/5, safe to merge) left this open from an earlier round. Candidate
selection tries the durable submission and then falls through to `_auto_best`
unconditionally, but only `auto_best` mode is validated to carry backend_id,
evaluation_set and objective. So a `submit`-mode run whose agent never wrote a
submission reached three bare asserts: an AssertionError with no diagnostic,
and under -O no check at all. It now declines and drops to `_pick_last`, the
intended last resort. Test reverts the guard to confirm it reproduces the
AssertionError.

Not fixed, deliberately: the same review flagged the unshielded status write in
_execute_tracked_job's Exception handler. Shielding it after `admitted.set()`
makes the common path worse -- shield schedules a task and therefore yields, so
the caller observes the job still QUEUED, which broke the admission-denial
test. Shielding it before `admitted.set()` deadlocks, so that ordering is
load-bearing. The review rates the consequence as a misleading status under a
narrow double-cancellation race that self-corrects on reload, which is cheaper
than either regression.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Greptile (5/5, safe to merge) named the two gaps on this PR.

UPSTREAM_MODEL_UNAVAILABLE had no tests. It is the taxonomy's most dangerous
silent failure -- unclassified, a model that is configured but not deployed
makes every call 404, the agent writes no answer, and each case is recorded as
an informative task failure, i.e. the harness scoring the candidate down for a
model that does not exist. Tests now pin the provider error codes it matches,
its terminating/not-a-sample/counts-toward-invalidity policy, and the
deliberate narrowness: a bare "does not exist" must stay unmatched, or it would
swallow "loading container: file does not exist".

load_build was annotated `-> dict` while returning `(dict, Path)`; the caller
unpacks two values. Corrected rather than merely added.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@varunursekar
varunursekar changed the base branch from pr2-add-vero to main July 28, 2026 21:21
@varunursekar
varunursekar dismissed shehabyasser-scale’s stale review July 28, 2026 21:21

The base branch was changed.

varunursekar and others added 2 commits July 28, 2026 14:41
Greptile flagged the raw-CancelledError handler: the refund is shielded against
cancellation but not against failing by itself, so an OSError from the ledger's
write propagates in place of the CancelledError. The caller's structured scope
never sees the teardown, and the reservation stays charged -- the exact leak the
handler was added to prevent.

It flagged one site; there are three, all the same shape. The typed
EvaluationCancelledError and EvaluationExecutionError handlers refund the same
way and lose their own exception identically. Only the third was reported, and
the regression test written for it actually exercised the first -- which is how
the other two surfaced. All three now chain the refund error and re-raise the
original, matching BudgetStore.refund.

Test reverts the guards to confirm the OSError replaces the cancellation
without them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread harness-engineering-bench/scripts/check_keys.py
@varunursekar
varunursekar requested a review from auag92 July 28, 2026 21:57
auag92
auag92 previously approved these changes Jul 28, 2026

@auag92 auag92 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

The infrastructure-failure branch was the one refund site still missing the
guard the other three got. It differs in shape: it sits on the success path
rather than in an `except`, so there is no bound exception to re-raise -- the
`raise EvaluationInfrastructureError(...)` runs after the refund, and an
OSError from the ledger's write preempted it entirely.

The consequence is a misclassification rather than a lost signal. The sidecar
maps this type to "infrastructure failure" for the agent; a bare OSError falls
through to the unmapped branch and is reported as "evaluation failed: OSError".
Nothing keys a retry on it, so that is the whole blast radius.

Build the failure before refunding so it always exists to raise, then chain the
refund's own error onto it, matching the three handlers above.
A missing rate-limit header reads as 0, and the label compared the two derived
capacities directly, so whichever axis was absent won: with no TPM header and
an RPM limit, `0 <= by_rpm` printed "TPM-bound" and would send someone to raise
a quota that was never the constraint.

`fits` already skipped zeros; only the label did not. Report the axis that
produced `fits`, and say so explicitly when the other header is missing rather
than implying both were read.

Greptile flagged this and proposed `by_tpm and by_tpm <= by_rpm`, which fixes
the absent-TPM case but still prints "RPM-bound" for the mirror case (a TPM
limit and no RPM header), because the `and` short-circuits to the same branch.
auag92
auag92 previously approved these changes Jul 28, 2026

@auag92 auag92 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

@varunursekar
varunursekar dismissed auag92’s stale review July 28, 2026 22:39

The merge-base changed after approval.

The main loop already asked whether the model accepts reasoning.effort before
sending it -- gpt-4o and friends answer HTTP 400 -- but the forced-final request
that fires when the 24-turn budget runs out sent it unconditionally. On a
non-reasoning target that turns the best-effort answer path into the lost data
point it was added to prevent.

Latent today: the target is pinned to gpt-5.4-mini and the grid varies the
optimizer model, not the target, so the branch cannot fire as configured.

Lift the check to a module-level helper and call it from both sites, so a third
request cannot quietly skip it. Same predicate the browsecomp-plus agent uses.
yash-scaleai
yash-scaleai previously approved these changes Jul 28, 2026

@yash-scaleai yash-scaleai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@varunursekar
varunursekar dismissed yash-scaleai’s stale review July 28, 2026 22:57

The merge-base changed after approval.

@varunursekar
varunursekar merged commit 64c71c6 into main Jul 28, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants